package com.getan.boot.module.system.service.persistent;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.getan.boot.common.enums.EnableStatus;
import com.getan.boot.common.utils.CollectionUtils;
import com.getan.boot.common.utils.MathUtils;
import com.getan.boot.common.utils.Preconditions;
import com.getan.boot.jdbc.service.GenericService;
import com.getan.boot.module.system.constant.ErrorCode;
import com.getan.boot.module.system.constant.PermissionTypeEnum;
import com.getan.boot.module.system.entity.PermissionEntity;
import com.getan.boot.module.system.entity.RolePermissionEntity;
import com.getan.boot.module.system.repository.PermissionRepository;
import com.getan.boot.module.system.service.cache.PermissionCacheService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 权限管理
 *
 * @author Bruce.Gong
 * @since 1.0.0-SNAPSHOT
 */
@Slf4j
@RequiredArgsConstructor
@Service
@Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
public class PermissionService extends GenericService<PermissionRepository, PermissionEntity> {

    private final PermissionCacheService permissionCacheService;
    private final RolePermissionService rolePermissionService;
    @Value(value = "${getan.cache.system.permission:true}")
    private boolean useCache;

    /**
     * 查询所有权限，以树结构返回
     *
     * @return 权限树
     */
    public List<PermissionEntity> tree() {
        List<PermissionEntity> deptList = list();
        return CollectionUtils.listTree(deptList, PermissionEntity::getId, PermissionEntity::getPid, PermissionEntity::getChildren, PermissionEntity::setChildren);
    }

    /**
     * 校验权限是否存在
     *
     * @return 权限信息
     */
    private PermissionEntity checkExists(Long id) {
        PermissionEntity db = getById(id);
        Preconditions.isNull(db, ErrorCode.PERM_NOT_EXISTS);
        return db;
    }

    /**
     * 校验权限是否存在
     */
    public void checkParentActive(Long id) {
        if (id == null || id.compareTo(0L) == 0) {
            return;
        }
        PermissionEntity db = getById(id);
        Preconditions.isNull(db, ErrorCode.PERM_PARENT_NOT_EXISTS);
        Preconditions.check(() -> EnableStatus.DISABLE.match(db.getStatus()), ErrorCode.PERM_PARENT_DISABLED);
        Preconditions.check(() -> PermissionTypeEnum.BUTTON.match(db.getType()), ErrorCode.PERM_PARENT_BUTTON);
    }

    /**
     * 校验权限状态
     * - 权限是否存在
     * - 权限状态是否可用
     *
     * @return 权限信息
     */
    private PermissionEntity checkActive(Long id) {
        PermissionEntity db = checkExists(id);
        Preconditions.check(() -> EnableStatus.DISABLE.match(db.getStatus()), ErrorCode.PERM_DISABLED);
        return db;
    }

    /**
     * 判断权限是否存在可用的子权限
     *
     * @param id 权限ID
     * @return true | false
     */
    private boolean hasChildren(Long id) {
        return exists(Wrappers.<PermissionEntity>lambdaQuery()
                .eq(PermissionEntity::getPid, id)
                .eq(PermissionEntity::getStatus, EnableStatus.ENABLE.getCode()));
    }

    /**
     * 检查是否存在子权限，如果存在子权限，则不能调整父权限，也不能删除或者停用
     *
     * @param id 权限ID
     */
    private void checkHasChildren(Long id) {
        Preconditions.check(() -> hasChildren(id), ErrorCode.PERM_HAS_CHILDREN);
    }

    /**
     * 判断是否可修改
     *
     * @param entity 权限
     * @return 权限信息
     */
    public PermissionEntity canUpdate(PermissionEntity entity) {
        PermissionEntity db = checkActive(entity.getId());
        // 父权限发生变化，检查父权限状态，检查是否有子权限
        boolean changeParent = !MathUtils.equals(db.getPid(), entity.getPid());
        if (changeParent) {
            checkParentActive(entity.getPid());
            checkHasChildren(db.getId());
        }
        boolean changeType = db.getType().compareTo(entity.getType()) != 0;
        if (!changeParent && changeType && PermissionTypeEnum.BUTTON.match(entity.getType())) {
            checkHasChildren(db.getId());
        }
        return db;
    }

    /**
     * 判断是否可删除
     *
     * @param id 权限ID
     * @return 权限信息
     */
    public PermissionEntity canDelete(Long id) {
        PermissionEntity db = checkExists(id);
        // 检查是否有子权限
        if (EnableStatus.ENABLE.match(db.getStatus())) {
            checkHasChildren(id);
        }
        return db;
    }

    /**
     * 判断是否可停用
     *
     * @param id 权限ID
     * @return 权限信息
     */
    public PermissionEntity canDisable(Long id) {
        PermissionEntity db = checkActive(id);
        // 检查是否有子权限
        checkHasChildren(id);
        return db;
    }

    /**
     * 判断是否可启用
     *
     * @param id 权限ID
     * @return 权限信息
     */
    public PermissionEntity canEnable(Long id) {
        PermissionEntity db = checkExists(id);
        Preconditions.check(() -> EnableStatus.ENABLE.match(db.getStatus()), ErrorCode.PERM_DISABLED);
        checkParentActive(db.getPid());
        return db;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deletePermission(Long id) {
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void disable(Long id) {
        update(Wrappers.<PermissionEntity>lambdaUpdate()
                .set(PermissionEntity::getStatus, EnableStatus.DISABLE.getCode())
                .eq(PermissionEntity::getId, id)
                .eq(PermissionEntity::getStatus, EnableStatus.ENABLE.getCode()));
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void enable(Long id) {
        update(Wrappers.<PermissionEntity>lambdaUpdate()
                .set(PermissionEntity::getStatus, EnableStatus.ENABLE.getCode())
                .eq(PermissionEntity::getId, id)
                .eq(PermissionEntity::getStatus, EnableStatus.DISABLE.getCode()));
    }

    // region 鉴权

    /**
     * 查询所有可用的权限列表
     */
    public List<PermissionEntity> queryPermissions() {
        if (useCache) {
            return permissionCacheService.cacheActive();
        } else {
            return list(Wrappers.<PermissionEntity>lambdaQuery()
                    .eq(PermissionEntity::getStatus, EnableStatus.ENABLE.getCode()));
        }
    }

    /**
     * 查询所有可用的权限列表
     */
    public List<PermissionEntity> queryPermissions(Collection<Long> permissionIds) {
        if (useCache) {
            return permissionCacheService.cacheActive().stream()
                    .filter(v -> permissionIds.contains(v.getId()))
                    .collect(Collectors.toList());
        } else {
            return list(Wrappers.<PermissionEntity>query()
                    .lambda().setEntityClass(PermissionEntity.class)
                    .in(PermissionEntity::getId, permissionIds)
                    .eq(PermissionEntity::getStatus, EnableStatus.ENABLE.getCode()));
        }
    }

    /**
     * 查询所有可用的权限列表
     */
    public Set<Long> queryRolePermissionIds(Set<Long> roleIds) {
        return rolePermissionService.listDistinctObjs(Wrappers.<RolePermissionEntity>query()
                .select("distinct permission_id")
                .lambda().setEntityClass(RolePermissionEntity.class)
                .in(RolePermissionEntity::getRoleId, roleIds), RolePermissionEntity::getPermissionId);
    }

    // endregion

    public void removeCache() {
        try {
            if (useCache) {
                permissionCacheService.removeCache();
            }
        } catch (Exception e) {
            log.error("删除缓存失败[permission]", e);
        }
    }

}
